package cn.edu.sjtu.se.dslab.component.data.util;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

import cn.edu.sjtu.se.dslab.component.data.DataAttribute;
import cn.edu.sjtu.se.dslab.component.data.DataType;
import cn.edu.sjtu.se.dslab.component.data.DomainEntity;
import cn.edu.sjtu.se.dslab.component.data.Operation;
import cn.edu.sjtu.se.dslab.component.data.xmi.XMIAttribute;
import cn.edu.sjtu.se.dslab.component.data.xmi.XMIDomainEntity;
import cn.edu.sjtu.se.dslab.component.data.xmi.XMIGeneralization;
import cn.edu.sjtu.se.dslab.component.data.xmi.XMIOperation;
import cn.edu.sjtu.se.dslab.component.method.InterfaceMethod;
import cn.edu.sjtu.se.dslab.pojo.CodeGenerator;
import cn.edu.sjtu.se.dslab.service.IDataTypeService;
import cn.edu.sjtu.se.dslab.service.IDomainEntityService;
import cn.edu.sjtu.se.dslab.util.Const;
import cn.edu.sjtu.se.dslab.util.MD5;

@Service("domainEntityXMIGenerator")
public class DomainEntityXMIGenerator  extends CodeGenerator {

	
	@Resource(name = "dataTypeService")
	IDataTypeService dataTypeService;
	
	@Resource(name = "domainEntityService")
	IDomainEntityService domainEntityService;
	
	private final static String ENTTTY_SET = "entitySet";
	private final static String TYPE_SET = "typeSet";
	
	private final static String Entity_XMI_TemplateFile = "domain_entity_xmi.vm";
	
	public DomainEntityXMIGenerator() {
		super();
	}

	public DomainEntityXMIGenerator(String templateFile) {
		super(templateFile);
	}
	/**
	 * 生成ID
	 * 格式：_iFVQ2HapEeO2zcNjgWu0yA
	 * @param data
	 * @return
	 */
	private String generate_iFVId(String data){
		return generateID("_iFV",data,19);
	}
	
	private String generateID(String prefix,String data,int length){
		MD5 md5 = new MD5();
		String uri = md5.getMD5ofStr(data);
		StringBuilder hash = new StringBuilder(prefix).append(uri.substring(0, length));
		return hash.toString();
	}
	/**
	 * 生成ID
	 * 格式：_hhrHXt5iEeOPI5YdMjNFlw
	 * @param data
	 * @return
	 */
	private String generate_hhrId(String data){
		return generateID("_hhr",data,19);
	}
	

	
	/**
	 * 生成GUID ID
	 * 格式：GUID+6024c6ab-fe9e-402e-954f-27aca6d3b5e4
	 * @param data
	 * @return
	 */
	private String generateGUIDId(String data){
		String prefix = "GUID+";
		MD5 md5 = new MD5();
		String uri = md5.getMD5ofStr(data);
		StringBuilder hash = new StringBuilder(prefix).append(uri.substring(0, 8));
		hash.append("-");
		hash.append(uri.substring(8, 12));
		hash.append("-");
		hash.append(uri.substring(12, 16));
		hash.append("-");
		hash.append(uri.substring(16, 20));
		hash.append("-");
		hash.append(uri.substring(20));
		return hash.toString();
	}
	
	
	private Set<XMIDomainEntity> convertDomainEntityToXmiVersion(DomainEntity entity){
		Map<String, XMIDomainEntity> resultMap = new HashMap<String, XMIDomainEntity>();
		//Set<XMIDomainEntity> resultSet  = new HashSet<XMIDomainEntity>();
		
		Set<DomainEntity> todoSet  = new HashSet<DomainEntity>();
		
		XMIDomainEntity xmiDomainEntity = new XMIDomainEntity();
		xmiDomainEntity.setFunId(generate_iFVId(entity.getName()));
		xmiDomainEntity.setUri(entity.getUri());
		xmiDomainEntity.setId(generateGUIDId(entity.getName()));
		xmiDomainEntity.setName(entity.getName());
		if (entity instanceof DataType) {
			xmiDomainEntity.setType("data_type");
			xmiDomainEntity.setDefType("uml:DataType");
		}else {
			xmiDomainEntity.setType("data_entity");
			xmiDomainEntity.setDefType("uml:Class");
		}
		xmiDomainEntity.setBlockId(generate_hhrId(entity.getName()+xmiDomainEntity.getType()));
		if (entity.getAttributes() != null) {
			Set<XMIAttribute> attributes  = new HashSet<XMIAttribute>();
			for (DataAttribute attribute : entity.getAttributes()) {
				XMIAttribute xmiAttribute = new XMIAttribute();
				xmiAttribute.setId(generateGUIDId(attribute.getName()));
				xmiAttribute.setName(attribute.getName());
				
				DomainEntity returnEntity = attribute.getType();
				DataType tempType = dataTypeService.getDataTypeById(returnEntity.getId());
				
				if (tempType != null && tempType.getCategory().equals(Const.DATA_TYPE_BASIC)) {
					xmiAttribute.setType(tempType.getXmiId());
				}else {
					xmiAttribute.setType(generateGUIDId(returnEntity.getName()));
				}
				
				xmiAttribute.setOwnerId(xmiDomainEntity.getId());
				attributes.add(xmiAttribute);
				if (tempType != null && !tempType.getCategory().equals(Const.DATA_TYPE_BASIC)) {
					todoSet.add(tempType);
				}else if (tempType == null){
					todoSet.add(returnEntity);
				}
			}
			xmiDomainEntity.setAttrs(attributes);
		}
		/***
		 * 目前暂只导出构造函数
		 */
		if (entity.getOpertions() != null) {
			Set<XMIOperation> xmiOperations  = new HashSet<XMIOperation>();
			for (Operation operation : entity.getOpertions()){
				if (operation.getInterfaceMethod() == null || !operation.getInterfaceMethod().getName().trim().equals(entity.getName())) {
					continue;
				}
				XMIOperation xmiOperation = new XMIOperation();
				xmiOperation.setClassId(xmiDomainEntity.getId());
				xmiOperation.setName(operation.getInterfaceMethod().getName());
				
				InterfaceMethod method = operation.getInterfaceMethod();
				xmiOperation.setId(generateGUIDId(method.getName()+method.getId()));
				if (method.getArguments() != null) {
					Set<XMIAttribute> params = new HashSet<XMIAttribute>();
					System.out.println("arguments:"+method.getArguments());
					String[] parts = method.getArguments().split(",");
					if (parts != null) {
						for (int i = 0; i < parts.length; i++) {
							String temp = parts[i].trim();
							if (temp != null && !temp.equals("")) {
								temp.replace("  ", " ");
								String[] array = temp.split(" ");
								System.out.println("array[0]:"+array[0]);
								DomainEntity type = domainEntityService.getDomainEntityByName(array[0].trim());
								if (type != null) {
									XMIAttribute attribute = new XMIAttribute();
									attribute.setId(generateGUIDId(temp+method.getName()));
									attribute.setName(array[1].trim());
									DataType type2 = dataTypeService.getDataTypeById(type.getId());
									if (type2 != null ) {
										attribute.setType(type2.getCategory().equals(Const.DATA_TYPE_BASIC)?
												type2.getXmiId() : generateGUIDId(type2.getName()));
										if (!type2.getCategory().equals(Const.DATA_TYPE_BASIC) ) {
											todoSet.add(type2);
										}
									}else {
										attribute.setType(generateGUIDId(type.getName()));
										todoSet.add(type);
									}
									attribute.setOwnerId(xmiOperation.getId());
									params.add(attribute);
								}
								
							}
						}
					}
					xmiOperation.setParamters(params);
				}else {
					xmiOperation.setParamters(null);
				}
				xmiOperations.add(xmiOperation);
			}
			xmiDomainEntity.setOperations(xmiOperations);
		}
		if (entity.getExtendsSet() != null) {
			Set<XMIGeneralization> generalizations = new HashSet<XMIGeneralization>();
			for (DomainEntity domainEntity : entity.getExtendsSet()) {
				XMIGeneralization generalization = new XMIGeneralization();
				generalization.setId(generateGUIDId(domainEntity.getName()+System.currentTimeMillis()));
				generalization.setSpecifivId(xmiDomainEntity.getId());
				generalization.setGeneralId(generateGUIDId(domainEntity.getName()));
				generalizations.add(generalization);
			}
			xmiDomainEntity.setGeneralizations(generalizations);
			todoSet.addAll(entity.getExtendsSet());
		}
		resultMap.put(xmiDomainEntity.getId(),xmiDomainEntity);
		for (DomainEntity domainEntity : todoSet) {
			Set<XMIDomainEntity> entities =  convertDomainEntityToXmiVersion(domainEntity);
			if (entities != null) {
				for (XMIDomainEntity domEntity: entities) {
					if (!resultMap.containsKey(domEntity.getId())) {
						resultMap.put(domEntity.getId(), domEntity);
					}
				}
			}
			
		}
		Set<XMIDomainEntity> resultSet = new HashSet<XMIDomainEntity>(resultMap.values());
		return resultSet;
	}
		
	
	public boolean generateEntity(DomainEntity entity, String targetFile) {
		if (entity == null) {
			System.out.println("error!!!");
		}
		
		DataType  type = dataTypeService.getDataTypeById(entity.getId());
		if (type != null) {
			entity = type;
		}
		// 加载template
		template = ve.getTemplate(Entity_XMI_TemplateFile);
		
		Set<XMIDomainEntity> set  = convertDomainEntityToXmiVersion(entity);
		System.out.println("set size:"+set.size());
		Set<XMIDomainEntity> entitySet  = new HashSet<XMIDomainEntity>();
		Set<XMIDomainEntity> typeSet  = new HashSet<XMIDomainEntity>();
		
		for (XMIDomainEntity xmiDomainEntity : set) {
			if (xmiDomainEntity.getType().equals("data_type")) {
				typeSet.add(xmiDomainEntity);
			}else {
				entitySet.add(xmiDomainEntity);
			}
		}
		System.out.println("entitySet size:"+entitySet.size());
		System.out.println("typeSet size:"+typeSet.size());
		vc.put(ENTTTY_SET, entitySet);
		vc.put(TYPE_SET, typeSet);
		
		FileWriter fWriter = null;
		try {
			File writeFile = getFile(targetFile);
			fWriter = new FileWriter(writeFile);
			if (template != null) {
				template.merge(vc, fWriter);
			}
		} catch (IOException ex) {
			ex.printStackTrace();
			return false;
		} finally {
			try {
				fWriter.flush();
				fWriter.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		return true;
	}
}
